#include <iostream>
#include <fstream>
#include <memory>
#include <stdexcept>
#include "../../include/raii.h"

// RAII 文件管理器示例
class FileManager {
private:
    std::string filename;
    //std::unique_ptr 是 C++11 引入的智能指针，用于管理动态分配的资源（如文件流对象），确保资源在不再需要时自动释放。
    //std::ofstream 是文件输入输出流对象，用于处理文本文件的读写操作。通过 file->is_open() 检查文件是否成功打开。
    std::unique_ptr<std::ofstream> file;
    
public:
    //构造函数: 使用 explicit 关键字声明，防止隐式类型转换，确保构造函数的参数必须显式传递。
    explicit FileManager(const std::string& name) : filename(name) {
        // std::make_unique 是一个函数模板，用于方便地创建并初始化一个 FileManager 对象的管理器。
        file = std::make_unique<std::ofstream>(filename);
        if (! file->is_open()) {
            throw std::runtime_error("无法打开文件: " + filename);
        }
        std::cout << "文件已打开: " << filename << std::endl;
    }
    
    //FileManager 类的析构函数声明
    ~FileManager() {
        //file：检查指针是否有效（非空）。
        if (file && file->is_open()) {
            file->close();
            std::cout << "文件已关闭: " << filename << std::endl;
        }
    }
    
    //禁用复制构造函数和赋值操作符，确保资源的唯一性
    //这行代码声明了一个拷贝构造函数，并将其标记为 = delete。这意味着：
    //禁止拷贝构造：FileManager 类的对象不能通过拷贝构造函数创建。任何尝试拷贝该类对象的操作都会在编译时被阻止。
    //显式禁用：使用 = delete 是一种显式禁用拷贝语义的方式，比传统的私有化拷贝构造函数更清晰。
    //关键设计决策：
    //1. RAII原则：FileManager 类可能是一个资源管理类（如文件句柄、内存等），遵循RAII（Resource Acquisition Is Initialization）原则。禁止拷贝可以避免资源的多重释放或竞争条件。
    //2. 单例或唯一所有权：如果 FileManager 管理的是唯一资源（如文件），禁止拷贝可以确保资源不会被意外共享或复制。
    //编程模式与最佳实践
    //1.禁用拷贝语义：这是现代C++中推荐的做法，用于明确表达类的设计意图（不可拷贝）。
    //2.替代方案：如果需要共享资源，可以考虑使用移动语义（std::move）或智能指针（如 std::shared_ptr）。
    //总结: 这行代码是C++中用于禁止拷贝构造的典型用法，适用于需要严格控制资源生命周期的场景，体现了现代C++的清晰设计和安全性。
    FileManager(const FileManager&) = delete;

    //FileManager& operator=(const FileManager&) 是一个拷贝赋值运算符的重载声明。
    //它的作用是为FileManager类的对象提供赋值操作的能力，允许将一个FileManager对象的值赋给另一个同类型的对象。
    //= delete表示显式删除该函数，即禁止编译器生成默认的拷贝赋值运算符实现。
    //这意味着FileManager类的对象不能通过赋值运算符进行拷贝赋值操作。

    //设计意图:
    //1.禁止拷贝赋值：
    //这种设计通常用于资源管理类（如RAII类），目的是防止对象的拷贝赋值可能导致资源管理问题（例如双重释放或资源泄漏）。
    //例如，如果FileManager类管理文件句柄或其他独占资源，拷贝赋值可能会导致多个对象试图管理同一资源，从而引发错误。
    //2.明确表达设计意图：
    //使用= delete语法明确告诉其他开发者，拷贝赋值操作是被禁止的，而不是遗漏实现。

    //关键组件:
    //1.FileManager&：
    //返回类型是FileManager的引用，这是拷贝赋值运算符的标准返回类型，支持链式赋值（如a = b = c）。
    //2.onst FileManager&：
    //参数类型是常量引用，表示传入的是一个不可修改的FileManager对象。
    //3.= delete：
    //C++11引入的特性，用于显式禁用某些函数（如拷贝构造函数、拷贝赋值运算符等）。

    FileManager& operator=(const FileManager&) = delete;
    
    // 支持移动语义
    FileManager(FileManager&& other) noexcept 
        : filename(std::move(other.filename)), file(std::move(other.file)) {
        std::cout << "FileManager 被移动" << std::endl;
    }
    
    void write(const std::string& content) {
        if (file && file->is_open()) {
            *file << content << std::endl;
            std::cout << "写入内容: " << content << std::endl;
        }
    }
};

// 数组管理器示例
//这段代码定义了一个模板类 SafeArray，使用了 C++ 的模板编程技术
template<typename T>
class SafeArray {
private:
    std::unique_ptr<T[]> data;
    size_t size;
    
public:
    explicit SafeArray(size_t s) : size(s) {
        data = std::make_unique<T[]>(size);
        std::cout << "创建数组，大小: " << size << std::endl;
    }
    
    ~SafeArray() {
        std::cout << "销毁数组，大小: " << size << std::endl;
    }
    
    //这段代码是一个C++中的运算符重载函数，具体是重载了数组的[]运算符。
    //作用：重载[]运算符，使得对象可以像数组一样通过下标访问元素。
    //返回值：返回类型为T&，即对模板类型T的引用，允许直接修改数组中的元素。
    //参数：size_t index，表示要访问的元素的索引。
    T& operator[](size_t index) {
        if (index >= size) {
            throw std::out_of_range("数组索引越界");
        }
        return data[index];
    }
    
    size_t getSize() const { return size; }
};

//使用示例：
namespace raii {
    void demonstrateRAII() {
        std::cout << "=== RAII 示例 ===" << std::endl;

        try {
            // 文件会在作用域结束时自动关闭
            FileManager fileManager("test.txt");
            fileManager.write("Hello, RAII!");
            fileManager.write("这是第二行");

            // 数组会在作用域结束时自动释放
            SafeArray<int> numbers(5);
            for (size_t i = 0; i < numbers.getSize(); ++i) {
                numbers[i] = static_cast<int>(i * 10);
            }

            std::cout << "数组内容: ";
            for (size_t i = 0; i < numbers.getSize(); ++i) {
                std::cout << numbers[i] << " ";
            }
            std::cout << std::endl;

            // 即使这里抛出异常，资源也会被正确释放
            // throw std::runtime_error("模拟异常");

        } catch (const std::exception& e) {
            std::cout << "捕获异常: " << e.what() << std::endl;
        }

        std::cout << "RAII 确保了资源的自动清理" << std::endl;
    }
}

// int main() {
//     demonstrateRAII();
//     return 0;
// }